package login

import (
	"fmt"
	"ginweb-admin/api/v1/code"
	"ginweb-admin/commons/jwtgo"
	"ginweb-admin/commons/response"
	"ginweb-admin/global"
	"ginweb-admin/model/context"
	"ginweb-admin/model/entity/sys"
	"ginweb-admin/model/vo"
	"ginweb-admin/utils"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/gookit/validate"
	"github.com/patrickmn/go-cache"
	"time"
)

// 登录接口
type LoginApi struct{}

// 登录接口处理
func (api *LoginApi) ToLogin(c *gin.Context) {

	// 准备接收用户数据的载体
	loginContext := context.LoginContext{}

	// 绑定参数
	err := c.ShouldBindJSON(&loginContext)
	if err != nil {
		response.Fail(60002, "参数绑定失败！", c)
		return
	}

	// 开始校验验证码是否正确
	verify := code.VerifyCode(loginContext.CodeId, loginContext.Code)
	if !verify {
		response.Fail(60002, "输入的验证码有误！", c)
		return
	}

	// 校验参数
	validation := validate.Struct(&loginContext)
	if !validation.Validate() {
		response.FailWithValidatorData(validation, c)
		return
	}

	// 调用service层业务方法
	// 判断用户输入的账号、手机号、用户名
	sysUser := sysUserService.LoginAccountAndPhoneAndNickname(loginContext.Account)
	// 如果查询的用户等于空，证明用户不存在，找到不此用户，输入的账号有误
	if sysUser == nil {
		response.Fail(60002, "输入的账号有误！", c)
		return
	}

	// 判断用户输入的密码和数据库的密码是否一致
	if sysUser.Password != utils.Md5Slat(loginContext.Password, sysUser.Slat) {
		response.Fail(60002, "输入的密码有误!", c)
		return
	}

	// 返回用户数据
	var loginVo vo.LoginVo
	loginVo.Uuid = sysUser.UUID
	loginVo.Avatar = sysUser.Avatar
	loginVo.UserName = sysUser.UserName

	// 根据用户ID查询对应的角色
	userRoles, err := sysUserRoleService.FindUserRole(sysUser.ID)
	if err != nil {
		response.FailWithMessage("找不到用户授权的角色！", c)
		return
	}

	// 生成token
	token := api.generateToken(c, userRoles[0].ID, userRoles[0].RoleCode, sysUser)

	// 判断是否有对应的角色
	if len(userRoles) > 0 {
		// 根据用户对应的角色ID查询对应的菜单
		roleMenus, _ := sysRoleMenuService.SelectRoleMenus(userRoles[0].ID)

		// 根据用户id查询用户的角色的权限
		permissions, _ := sysRoleApiService.SelectRoleApis(userRoles[0].ID)

		// uuid用于挤下线
		uuid := utils.GetUUID()
		// 设置本地缓存
		global.Cache.Set(fmt.Sprintf("LocalCache:Login:%d", sysUser.ID), uuid, cache.NoExpiration)

		response.Ok(map[string]any{
			"user":        loginVo,
			"token":       token,
			"uuid":        uuid,
			"roles":       userRoles,
			"roleMenus":   sysMenuService.Tree(roleMenus, 0),
			"permissions": permissions}, c)

	} else {
		response.Fail(80001, "暂无授权信息！", c)
	}
}

/**
 * @Author kong
 * @Date 2023/12/27
 * @Description 根据用户信息创建Token
 */
func (api LoginApi) generateToken(c *gin.Context, roleId uint, roleCode string, sysUser *sys.SysUser) string {
	// 设置token续期的时间
	bf, _ := utils.ParseDuration("1d")
	ep, _ := utils.ParseDuration("7d")

	// 生成token
	token, err2 := myJwt.CreateToken(jwtgo.CustomClaims{
		sysUser.ID,
		sysUser.Account,
		roleId,
		roleCode,
		int64(bf / time.Second),
		jwt.StandardClaims{
			Audience:  "KONG",                                   // 受众
			Issuer:    "KONG-ADMIN",                             // 签发者
			IssuedAt:  time.Now().Unix(),                        // 签发时间
			NotBefore: time.Now().Add(-10 * time.Second).Unix(), // 生效时间
			ExpiresAt: time.Now().Add(ep).Unix(),                // 过期时间
		},
	})
	fmt.Println("当前时间是：", time.Now().Unix())
	fmt.Println("签发时间：" + time.Now().Format("2006-01-02 15:04:05"))
	fmt.Println("生效时间：" + time.Now().Add(-10*time.Second).Format("2006-01-02 15:04:05"))
	fmt.Println("过期时间：" + time.Now().Add(ep).Format("2006-01-02 15:04:05"))
	if err2 != nil {
		response.Fail(60002, "token创建失败", c)
	}

	return token
}
